#include <iostream>
#include <list>
#include <boost/lexical_cast.hpp>

#include "cfg_callbacks.h"

using namespace pnapi;

void CfgCallbacks::OnDocumentBegin(Context& context, std::string& file_name)
{
}
void CfgCallbacks::OnDocumentEnd(Context& context)
{
}
void CfgCallbacks::OnFunctionBegin(Context& context, std::string& name, std::string& id)
{
    assert(context.state_ == Context::OUT_OF_FUNCTION);
    context.cur_func_id_ = id;
    context.cur_func_entry_ =  &context.net_.createPlace(id + "entry");
    context.state_ = Context::IN_FUNCTION;
    std::cout << "OnFunctionBegin\n";
}
void CfgCallbacks::OnFunctionEnd(Context& context)
{
    assert(context.state_ != Context::OUT_OF_FUNCTION);
    Place& func_exit_place = context.net_.createPlace(context.cur_func_id_ + "exit");
    // to link all blocks
    for (std::list<std::pair<int, int> >::iterator it = context.block_links_.begin();
        it != context.block_links_.end();
         ++it) {
        Place* from = context.cur_blocks_[it->first];
        Place* to = context.cur_blocks_[it->second];
        Transition& t = context.net_.createTransition(from->getName() + to->getName());
        context.net_.createArc(*from, t);
        context.net_.createArc(t, *to);
    }
    //to link last block with fuct exit
    if (context.state_ == Context::IN_BLOCK) {
        Place* from = context.cur_blocks_[context.cur_block_id_];
        Transition& t = context.net_.createTransition(from->getName() + func_exit_place.getName());
        context.net_.createArc(*from, t);
        context.net_.createArc(t, func_exit_place);
    }

    context.state_ = Context::OUT_OF_FUNCTION;

    context.Reset();

    std::cout << "OnFunctionEnd\n";
}
void CfgCallbacks::OnBlock(Context& context, int id)
{
    assert(context.state_!= Context::OUT_OF_FUNCTION);
    Place& cur_block = context.net_.createPlace(context.cur_func_id_ + boost::lexical_cast<std::string>(id));
    context.cur_blocks_[id]  = &cur_block;
    if (context.state_ == Context::IN_FUNCTION) {
        Transition & t = context.net_.createTransition(context.cur_func_entry_->getName() + context.cur_blocks_[id]->getName());
        context.net_.createArc(*context.cur_func_entry_, t);
        context.net_.createArc(t, cur_block);
    }

    context.state_ = Context::IN_BLOCK;
    std::cout << "OnBlock " << id << "\n";
}
void CfgCallbacks::OnGoto(Context& context, int to)
{
    context.block_links_.push_back(std::pair<int, int>(context.cur_block_id_, to));
    std::cout << "OnGoto " << to << "\n";
}
void CfgCallbacks::AddCodeLine(Context& context, std::string& code_line)
{
    std::cout << "OnAddCodeLine " << code_line << " \n";
}

